/**
 * Title:		Pond.java
 * Description: This class implements the Pond Object and Pond logic 
 * using Java Swing. 
 * Also this class coordinates several Frogs and drawings.
 * 
 * @version		1.0 May 2009
 * @author		Hidemitsu Izawa (hi2136@columbia.edu)
 */

package kfrog;

import java.awt.*;
import java.awt.event.*;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Vector;
import java.util.Iterator;

public class Pond extends JPanel /*implements WindowListener*/{

	private static final long serialVersionUID = 4889429169230081219L;
	/**
	 * fields
	 */
    private BufferedImage bimg;
    private Vector<FrogFactory> froggy;	// must be atomic.
    private int numberOfTerminatedFrog=0;
    private int WIDTH;
    private int HEIGHT;
    private Color pondColor=Color.white;// default value = white
    private boolean isDisplayDebugMessage;
    private int numberOfFrog = 0;
    private JFileChooser dialog;
    private Rectangle clipRegion;

    /**
     * constructor
     */
    public Pond(int width, int height) {
    	this.isDisplayDebugMessage = 
    		KFrogMain.debug || KFrogMain.test || KFrogMain.testSemantics;
		/** for file chooser */
    	dialog=new JFileChooser();
		FileFilter filter = 
			new FileNameExtensionFilter("GIF IMAGE","gif","GIF");
		dialog.addChoosableFileFilter(filter);
		/** for pond size */
    	this.WIDTH = width;
    	this.HEIGHT = height;
		bimg = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
	    Graphics canvas = bimg.createGraphics();
		canvas.setColor(pondColor);
		canvas.fillRect(0, 0, WIDTH, HEIGHT);
		clipRegion = null;
		froggy = new Vector<FrogFactory>();
		
		JFrame app = new JFrame("KFrog Viewer");
		
		/** for closing button */
		app.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
			    System.exit(0);
			}
		});
		
		/** for minimizing window */
		app.addWindowListener(new WindowAdapter() {
			public void windowDeiconified(WindowEvent e){
				partlyRepaint();
			}
		});
		
		/** for save dialog */
		JMenu saveMenu = new JMenu("File(F)");
		ActionListener listener1 = new ActionListener(){
			public void actionPerformed(ActionEvent e){
				File f = getFile(JFileChooser.OPEN_DIALOG);
				if(f==null)return;
				try {
					ImageIO.write(bimg, "gif", f);
				} catch (Exception e2) {
					JOptionPane.showMessageDialog(null, e2.getMessage());
				}
			}
		};
		JMenuBar bar = new JMenuBar();
		bar.add(saveMenu);
		app.setJMenuBar(bar);
		saveMenu.add("save").addActionListener(listener1);
		
		/** for help dialog */
		JMenu helpMenu = new JMenu("Help(H)");
		ActionListener listener2 = new ActionListener(){
			public void actionPerformed(ActionEvent e){
				JOptionPane.showMessageDialog(null,
						"KFrog Language Ver1.0 Produced by Team Kajika 2009",
						"Version Information",
						JOptionPane.INFORMATION_MESSAGE);
				
			}
		};
		bar.add(helpMenu);
		app.setJMenuBar(bar);
		helpMenu.add("version").addActionListener(listener2);

		/** set pond size */
		app.setSize(WIDTH,HEIGHT); //JFrame app
		app.getContentPane().setPreferredSize(new Dimension(WIDTH,HEIGHT));
		app.setResizable(false);
		app.getContentPane().add(this);//important
		app.pack();//important
		app.setVisible(true);

		/** window icon settings */
        Image iconImage = 
           Toolkit.getDefaultToolkit().createImage(Const.RED_FROG_IMG_FILENAME);
        app.setIconImage(iconImage);
        app.pack();
        setVisible(true);

		
		/** debug-output */
		if(isDisplayDebugMessage){
			System.out.println("pondsize "+ WIDTH + "," + HEIGHT);
		}
    }
    
    
    /**
     * methods
     */
    
    /** set pond color */
    private void setPondColor(Color color){
    	this.pondColor = color;
	    Graphics canvas = bimg.createGraphics();
		canvas.setColor(color);
		canvas.fillRect(0, 0, WIDTH, HEIGHT);
    }
    
    
    /** set pond color */
    public void setPondColor(String color){
    	if(color.equals(Const.RED)){
    		setPondColor(Color.red);
    	}
    	else if(color.equals(Const.GREEN)){
    		setPondColor(Color.green);
    	}
    	else if(color.equals(Const.BLUE)){
    		setPondColor(Color.blue);
    	}
    	else if(color.equals(Const.YELLOW)){
    		setPondColor(Color.yellow);
    	}
    	else if(color.equals(Const.BLACK)){
    		setPondColor(Color.black);
    	}	
    	else{
    		setPondColor(Color.white);
    	}
    	/** debug-output */
    	if(isDisplayDebugMessage){
        	System.out.println("pondcolor "+color);
    	}
    }
    
    
    /** clearscreen command */
    public void clearscreen(){
    	Graphics2D g2 = (Graphics2D)bimg.createGraphics();
    	g2.setBackground(pondColor);
    	g2.clearRect(0, 0, getWidth(), getHeight());
    	repaint();
    	//debug-output
    	if(isDisplayDebugMessage){
        	System.out.println("clearscreen");
    	}
    }
    
    
    /** reset command 
     * (clear screen + reset location and direction for each frog) */
    public void reset(){
    	clearscreen();
    	//reset location and direction for each frog
    	Iterator<FrogFactory> ite = froggy.iterator();
    	while(ite.hasNext()){
    		FrogFactory frog = ite.next();
    		frog.resetLocationAndDirection();
    	}
    	//debug-output
    	if(isDisplayDebugMessage){
        	System.out.println("reset");
    	}
    }
 
    
    /** add frog */
    public void addFrog(FrogFactory frog) {
    	froggy.add(frog);
    }

    
    /** make Graphics object */
    public Graphics makeCanvas() {
        return bimg.createGraphics();
    }
    

    /** set clip */
    public synchronized void setClip(int x0, int y0, int margin) {
        Rectangle r = new Rectangle(x0 - margin,
        							y0 - margin,
        							margin * 2,
        							margin * 2);
        if (clipRegion == null){//clipRegion is Rectangle class
            clipRegion = r;
        }
        else{
            clipRegion.add(r);
        }
    }

    
    /** actual paint method 
     * must by synchronized */
    public synchronized void partlyRepaint() {
        Rectangle r = clipRegion;
        clipRegion = null;
        if (r != null){//most case
            repaint(r);
        }
        else{//incase...
            repaint();//-> paintComponent()
        }
    }

    
    /** override paintComponent method */
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawImage(bimg, 0, 0, this);
        
        /** do not use iterator */
        for(int i=0;i<froggy.size();i++){
        	FrogFactory frogfactory = (FrogFactory)froggy.get(i);
        	frogfactory.paint(g);//drawing frog icon
        }
    }
    
    
    /** get pond width */
    public int getPondWidth(){
    	return WIDTH;
    }
    
    
    /**get pond height */
    public int getPondHeight(){
    	return HEIGHT;
    }
    
    
    /**get number of frog */
    public synchronized int getNumberOfFrog(){
    	this.numberOfFrog ++;
    	return this.numberOfFrog;
    }
    
    
    /** for file chooser */
    File getFile(int type){
		dialog.setDialogTitle("Save");
		dialog.setDialogType(JFileChooser.SAVE_DIALOG);
		int flg=dialog.showSaveDialog(this);
		if(flg==JFileChooser.APPROVE_OPTION){
			File selectedFile = dialog.getSelectedFile();
			String selectedFileName = selectedFile.toString();
			if(selectedFileName.contains("gif") || 
					selectedFileName.contains("GIF")){
				return dialog.getSelectedFile();
			}
			else{
				return new File(dialog.getSelectedFile()+".gif");
			}
		}else{
			return null;
		}
	}
    
    
    /** called by the frog in finishing execution 
     * this method is for terminating window after finished execution */
    public synchronized void terminateNotification(){
    	this.numberOfTerminatedFrog++;
    	/** if all frog have finished execution */
    	if(this.numberOfTerminatedFrog == this.numberOfFrog){
    		if(isDisplayDebugMessage){//only if it is debugging -> close window
        		try {
    				Thread.sleep(3000);//wait 3 sec
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
        		System.exit(0);//close window
    		}
    	}
    }
}
